package com.mytijian.openapi.adapter.dianping.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.mytijian.openapi.adapter.dianping.client.DzopenUtils;
import com.mytijian.openapi.adapter.dianping.consts.DzopenConsts;
import com.mytijian.openapi.adapter.dianping.dao.DzopenShopAuthDAO;
import com.mytijian.openapi.adapter.dianping.dao.DzopenShopAuthRelDAO;
import com.mytijian.openapi.adapter.dianping.dao.dataobject.DzopenShopAuthDO;
import com.mytijian.openapi.adapter.dianping.dao.dataobject.DzopenShopAuthRelDO;
import com.mytijian.openapi.adapter.dianping.dao.param.DzopenShopAuthDAOQuery;
import com.mytijian.openapi.adapter.dianping.exceptions.DzopenErrorInfo;
import com.mytijian.openapi.adapter.dianping.exceptions.DzopenException;
import com.mytijian.openapi.adapter.dianping.inner.param.DzRefershSessionParam;
import com.mytijian.openapi.adapter.dianping.inner.result.DzrefershSessionResult;
import com.mytijian.openapi.adapter.dianping.param.DzopenShopAuthParam;
import com.mytijian.openapi.adapter.dianping.param.DzopenShopAuthScopeDetail;
import com.mytijian.openapi.adapter.dianping.service.DzopenShopAuthService;
import com.mytijian.utils.DateUtils;

@Component
public class DzopenShopAuthServiceImpl implements DzopenShopAuthService {

	private Logger logger = LoggerFactory.getLogger(DzopenShopAuthServiceImpl.class);

	/**
	 * FIXME 授权关系应该作为服务而不是简单的DAO
	 */
	@Autowired
	private DzopenShopAuthRelDAO dzopenShopAuthRelDAO;

	@Autowired
	private DzopenShopAuthDAO dzopenShopAuthDAO;
	
	@Value("${dzopen.signkey}")
	private String signkey;
	
	@Value("${dzopen.appkey}")
	private String appkey;

	@Override
	public String getSession(String hospitalId) {
		if (!StringUtils.isNumeric(hospitalId)) {
			logger.error("体检中心id {} 不是一个数字", hospitalId);
			throw new DzopenException(DzopenErrorInfo.ERROR);
		}
		return getSession(Integer.valueOf(hospitalId));
	}

	@Override
	public String getSession(Integer hospitalId) {
		DzopenShopAuthRelDO reldo = dzopenShopAuthRelDAO.select(hospitalId);
		if (reldo == null) {
			logger.error("体检中心 id:{} 授权session不存在。");
			throw new DzopenException(DzopenErrorInfo.ERROR);
		}
		DzopenShopAuthDAOQuery query = new DzopenShopAuthDAOQuery();
		query.setId(reldo.getAuthId());
		List<DzopenShopAuthDO> list = dzopenShopAuthDAO.select(query);
		if (list == null || list.isEmpty() || list.size() > 1) {
			logger.error("体检中心 id:{} 未找到session或找到多条session。 session count is: {}", hospitalId,
					list == null ? 0 : list.size());
			throw new DzopenException(DzopenErrorInfo.ERROR);
		}
		return list.get(0).getCallbackSession();
	}



	/**
	 * 简单授权管理。 后续需要优化
	 */
	@Override
	@Transactional
	public void doAuth(DzopenShopAuthParam param) {
		Date today = DateUtils.parse(DateUtils.format(new Date()));
		DzopenShopAuthDO auth = new DzopenShopAuthDO();
		auth.setCallbackSession(param.getCallbackSession());
		auth.setRefershSessionRemaining(12);
		Date expiresEnd = new Date(today.getTime()+(Long.valueOf(param.getExpiresIn())+1)*1000);
		auth.setExpiresEnd(expiresEnd);
		auth.setExpiresIn(param.getExpiresIn());
		auth.setRefreshSession(param.getRefreshSession());
		auth.setScope(param.getScope());
		auth.setScopeDetail(param.getScopeDetail());
		dzopenShopAuthDAO.insert(auth);

		int authId = auth.getId();

		String scopeDetail = param.getScopeDetail();
		List<DzopenShopAuthScopeDetail> details = JSON.parseArray(scopeDetail, DzopenShopAuthScopeDetail.class);

		List<Integer> hospitalIds = new ArrayList<>();
		for (DzopenShopAuthScopeDetail detail : details) {
			Integer hospitalId = Integer.valueOf(detail.getApp_shop_id());
			hospitalIds.add(hospitalId);
			logger.info("hospitalId={}",hospitalId);
		}

		dzopenShopAuthRelDAO.deleteByHospitalIds(hospitalIds);
		dzopenShopAuthRelDAO.insert(authId, hospitalIds);

	}

	private final long preUpdateDate = 5;
	
	@Override
	public void checkUpdate() {
		
		Date today = DateUtils.parse(DateUtils.format(new Date()));
		List<DzopenShopAuthDO> list = dzopenShopAuthDAO.selectAll();

		for (DzopenShopAuthDO auth : list) {
			if (auth.getRefershSessionRemaining() ==0 ) {
				logger.warn("【美团点评】 刷新session次数已用完 session={}",auth.getCallbackSession());
				// TODO 先简单实现店铺刷新功能
				// 后续这边要给出报警
				continue;
			}
			
			Date end = auth.getExpiresEnd();
			long rem = end.getTime() - today.getTime();
			
			if (rem<= preUpdateDate*86400L*1000L) {
				// 延长有效期
				DzRefershSessionParam param = new DzRefershSessionParam();
				param.setAppKey(appkey);
				param.setAppSecret(signkey);
				param.setGrantType("refresh_token");
				param.setRefreshToken(auth.getRefreshSession());
				DzrefershSessionResult result = DzopenUtils.sendRequest(DzopenConsts.Apis.AuthToken, signkey, param, DzrefershSessionResult.class);

				// 判断返回值是否正确
				if (result!=null  && "200".equals(result.getCode())) {
					Date newEnd = new Date(today.getTime()+Long.valueOf(result.getExpires_in()));
					auth.setCallbackSession(result.getAccess_token());
					auth.setRefreshSession(result.getRefresh_token());
					auth.setRefershSessionRemaining(auth.getRefershSessionRemaining()-1);
					auth.setExpiresEnd(newEnd);
					dzopenShopAuthDAO.update(auth);
					logger.info("[美团点评] 刷新 session成功 参数{} 接口返回{}",
							ToStringBuilder.reflectionToString(param),
							ToStringBuilder.reflectionToString(result));
				} else {
					logger.error("!!! [美团点评] 刷新 session失败 参数 {} 接口返回{} ", 
							ToStringBuilder.reflectionToString(param),
							ToStringBuilder.reflectionToString(result));
				}
			}
		}
	}
}
